// 版权所有2009 Go作者。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// 包测试为Go包的自动测试提供支持。
// 它打算与“go test”命令配合使用，该命令自动执行
// 任何形式的函数
// func TestXxx（*testing.T）
// 其中Xxx不以小写字母开头。函数名
// 用于标识测试例程。
// 
// 在这些函数中，使用错误、失败或相关方法来表示失败。
// 
// 要编写新的测试套件，请创建一个名称以_test结尾的文件。确保
// 包含此处描述的TestXxx函数。将该文件放入与被测试文件相同的
// 包中。该文件将被排除在常规
// 包构建之外，但在运行“go test”命令时将被包括在内。
// 有关详细信息，请运行“go help test”和“go help testflag”。
// 
// 一个简单的测试函数如下：
// 
// func TestAbs（t*testing.t）{
// got:=Abs（-1）
// if got！=1{
// t.Errorf（“Abs 1）=%d；want 1”，got）
// 
// 函数形式为
// func BenchmarkXxx（*testing.B）
// 被视为基准测试，当提供
// its-bench标志时，通过“go test”命令执行。基准测试是按顺序运行的。
// 
// 有关测试标志的说明，请参阅
// https:
// 
// 一个示例基准函数如下所示：
// func BenchmarkRandInt（b*testing.b）{
// for i:=0；i<b.N；i++{
// rand.Int 
// }
// }
// 
// 基准函数必须运行目标代码b.N次。
// 在基准测试执行期间，b.N会被调整，直到基准测试函数持续
// 足够长的时间，以便可靠地计时。输出
// BenchmarkRandInt-8 68453040 17.8 ns/op 
// 意味着循环以每个循环17.8 ns的速度运行68453040次。
// 
// 如果基准测试在运行前需要一些昂贵的设置，计时器
// 可能被重置：
// 
// func BenchmarkBigLen（b*testing.b）{
// big:=NewBig（）
// b.ResetTimer（）
// 对于i:=0；i<b.N；i++{
// big.Lenbenchmark需要在并行设置下测试性能，可以使用
// RunParallel helper函数；此类基准测试旨在与
// go test-cpu标志一起使用：
// 
// func BenchmarkTemplateParallel（b*testing.b）{
// temp:=template.Must（template.New（“test”）.Parse（“你好，{}}！”）
// b.RunParallel（func（pb*testing.pb）{
// var buf bytes.Buffer 
// for pb.Next（）{
// buf.Reset（）
// temple.Execute（&buf，“World”）
// }基准测试结果格式的详细说明见
// https:
// 
// 在
// https:
// 统计稳健的A/B比较。
// 
// 示例
// 
// 该包还运行并验证示例代码。示例函数可能包含以“Output:”开头的结束行注释，并与运行测试时函数的标准输出进行比较。（比较
// 忽略前导和尾随空格。）下面是一个例子：
// 
// func ExampleHello（）{
// fmt.Println（“hello”）
// /输出：hello 
// }
// /
// func exampleAltations（）{
// /fmt.Println（“hello，and”）
// /fmt.Println（“再见”）
// /输出：
// /您好，
// 
// 注释前缀“无序输出：”类似于“输出：”，但匹配任何
// 行顺序：
// 
// func ExamplePerm（）{
// for u，value:=range Perm（5）{
// fmt.Println（value）
// }
// /无序输出：4 
// /2 
// /1 
// /0 
// }
// 
// 编译但不执行没有输出注释的示例函数。
// 
// 为包、函数F、类型T和
// 类型T上的方法M声明示例的命名约定是：
// 
// func Example（）{…}
// func ExampleF（）{…}
// func ExampleT（）{…}
// func ExampleT_M（）{…}
// 
// 一个包/类型/函数/方法的多个示例函数可能由
// 在名称后面附加一个不同的后缀提供。后缀必须以
// 小写字母开头。
// 
// func示例_suffix（）{…}
// func ExampleF_suffix（）{…}
// func ExampleT_suffix（）{…}
// func ExampleT_M_suffix（）{…}
// 
// 当整个测试文件包含单个
// 示例函数、至少一个其他函数、类型、变量或常量
// 声明，并且没有测试或基准函数时，它将作为示例显示。
// 
// Fuzzing 
// 
// “go test”和测试包支持Fuzzing，这是一种测试技术，其中
// /使用随机生成的输入调用函数，以查找单元测试预期的错误。
// 
// 形式为
// func FuzzXxx（*testing.F）
// 的函数被视为模糊测试。
// 
// 例如：
// 
// func FuzzHex（f*testing.f）{
// For z，seed:=range[]]字节{0}，{9}，{0xa}，{0xf}，{1,2,3,4}{
// f.Add（seed）
// }
// f.Fuzz（func（t*testing.t，in[]字节）{
// enc enc enc hex.EncodeToString（in）
// if err
// }
// /如果！字节。Equal（in，out）{
// t.Fatalf（“%v:往返后不相等：%v”，in，out）
// }
// }）
// }
// 
// 模糊测试维护一个种子库，或一组由
// default运行的输入，并可以种子生成。种子输入可以由
// 调用（*F）注册。在包含
// （其中<Name>是模糊测试的名称）目录中。种子输入是可选的，但当提供一组具有良好
// 模糊测试的包中，添加或通过将文件存储在testdata/fuzz/<Name>
// 错误。这些种子输入还可以作为通过模糊识别的错误
// 代码覆盖率的小种子输入时，模糊引擎可能会更有效地发现
// 的回归测试。
// 
// 传递给（*F）的函数。模糊测试中的模糊被视为模糊
// 目标。模糊目标必须接受一个*T参数，后跟一个或多个
// 随机输入参数。传递给（*F）的参数类型。Add必须与这些参数的类型相同。模糊目标可能会向
// 发出信号，表明它发现了一个与测试相同的问题：通过调用T.Fail（或任何类似于T.Error或T.Fatal调用它的
// 方法）或通过恐慌。
// 
// 启用模糊化时（通过将-fuzz标志设置为与特定模糊测试匹配的正则表达式
// 来），将使用参数
// 通过反复随机更改种子输入生成。在
// 支持的平台上，“go test”使用模糊
// 覆盖检测编译测试可执行文件。模糊引擎使用该工具来查找和缓存扩展覆盖范围的输入，从而增加查找错误的可能性。如果模糊目标对给定输入失败，则模糊引擎
// 将导致失败的输入写入包目录中
// testdata/fuzz/<Name>目录下的文件。此文件稍后用作
// 种子输入。如果无法在该位置写入文件（例如，
// 因为目录是只读的），则模糊引擎会将文件写入构建缓存中的模糊缓存目录
// 中。
// 
// 禁用模糊化时，将使用种子输入
// 调用模糊目标，并在F中注册。从testdata/fuzz/<Name>添加和种子输入。在这个
// 模式下，fuzz测试的行为与常规测试非常相似，子测试是用F.fuzz而不是T.Run启动的。
// 参见https:
// 
// 跳过
// 
// 可以在运行时调用
// 跳过测试或基准测试*T或*B的Skip方法：
// 
// 函数测试耗时（T*testing.T）{
// if testing.Short（）{
// /}
// /。。。
// }
// /
// 如果输入无效，*T的Skip方法可用于模糊目标，但不应被视为失败输入。例如：
// 
// func FuzzJSONMarshalling（f*testing.f）{
// f.Fuzz（func（t*testing.t，b[]字节）{
// var v接口{}
// if err json:=json。拆封（b&v）；呃！=nil{
// t.Skip（）
// }
// /如果z，错误：=json。元帅（五）；呃！=无{
// t.Error（“封送员：%v”，err）
// }
// }）
// }
// 
// 子测试和子基准
// 
// t和B的运行方法允许定义子测试和子基准，
// 无需为每个函数定义单独的函数。这允许使用
// 类似于表驱动的基准测试和创建分层测试。
// 它还提供了一种共享常见设置和拆卸代码的方法：
// 
// func TestFoo（t*testing.t）{
// <setup code>
// /t.Run（“a=1”，func（t*testing.t）{…}）
// t.Run（“A=2”，func（t*testing.t）{…}）
// t.Run（“B=1”，func（t*testing.t）{…}）
// <分解代码>
// }
// 
// 每个子测试和子基准都有一个唯一的名称：顶级测试的名称
// 和传递给运行的名称序列的组合，用
// 斜杠分隔，带有可选的尾随序列号以消除歧义。
// 
// 命令行标志-run、-bench和-fuzz的参数是一个与测试名称匹配的未编排的常规
// 表达式。对于包含多个斜杠分隔的
// 元素的测试，例如子测试，参数本身是斜杠分隔的，
// 表达式依次匹配每个名称元素。因为它是未编排的，所以
// 空表达式匹配任何字符串。例如，使用“匹配”来表示“其名称包含”：
// 
// go test-run“”#运行所有测试。
// go test-run Foo#运行与“Foo”匹配的顶级测试，例如“TestFooBar”。
// go test-run Foo/A=#对于匹配“Foo”的顶级测试，运行匹配“A=”的子测试。
// go test-run/A=1#对于所有顶级测试，运行与“A=1”匹配的子测试。
// go test-fuzz FuzzFoo#fuzz匹配“FuzzFoo”的目标
// 
// run参数也可以用于运行种子
// 语料库中的特定值，以进行调试。例如：
// go test-run=FuzzFoo/9ddb952d9814 
// 
// 为了模糊目标，可以同时设置-fuzz和-run标志，但是
// 跳过所有其他测试的执行。
// 
// 子测试也可用于控制并行性。父测试只有在所有子测试完成后才能完成。在本例中，所有测试都是
// 彼此并行运行，并且仅彼此并行运行，不考虑
// 其他可能定义的顶级测试：
// 
// func TestGroupedParallel（t*testing.t）{
// for，tc:=范围测试{
// tc:=tc
// t.Run（）
// /。。。
// /}）
// /}
// /}
// 
// 如果超过8128个并发Goroutine，
// 那么在使用-race标志集运行并行测试时要小心。
// 
// Run在并行子测试完成之前不会返回，提供了一种在一组并行测试之后进行清理的方法：
// 
// func TestTeardownParallel（t*testing.t）{
// 
// t.Run（“group”，func（t*testing.t）{
// t.Run（“Test2”，parallelTest2）
// t.Run（“Test3，parallelTest3）
// }）
// <分解代码>
// }
// 
// 主
// 
// 在执行之前或之后。有时还需要控制
// 主线程上运行的代码。为了支持这些和其他情况，如果测试文件包含一个函数：
// 
// func TestMain（m*testing.m）
// 
// 那么生成的测试将调用TestMain（m），而不是直接运行测试或基准测试。TestMain在主goroutine中运行，可以执行任何设置
// 并且在调用m.Run时需要进行拆卸。m、 Run将返回一个可能被传递到操作系统的退出
// 代码。出口如果TestMain返回，测试包装
// 将把m.Run的结果传递给os。退出。
// 
// 调用TestMain时，标记。解析尚未运行。如果TestMain依赖于
// 命令行标志，包括测试包的标志，那么它应该调用
// 标志。显式解析。命令行标志始终由运行的时间测试
// 或基准函数解析。
// 
// TestMain的一个简单实现是：
// 
// func TestMain（m*testing.m）{
// /call flag.Parse（），如果TestMain使用标志
// /os.Exit（m.Run（））
// }
// 测试需求，普通测试功能就足够了。
package testing

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"internal/race"
	"io"
	"math/rand"
	"os"
	"reflect"
	"runtime"
	"runtime/debug"
	"runtime/trace"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
	"time"
	"unicode"
	"unicode/utf8"
)

var initRan bool

// 初始化寄存器测试标志。这些标志在运行测试函数之前由
// 命令“go test”自动注册，因此在不使用“go test”调用Benchmark等函数时，只需要使用Init。
// 
// Init如果已经被调用，则无效。
func Init() {
	if initRan {
		return
	}
	initRan = true
	// 短标志要求测试运行得更快，但其功能
	// 由测试编写者自己提供。测试包就是它的
	// 主页。所有的。bash安装脚本将其设置为使安装更加高效，但默认情况下，该标志处于关闭状态，因此普通的“go test”将对包进行完整测试。
	short = flag.Bool("test.short", false, "run smaller test suite to save time")

	// failfast标志请求在第一次测试失败后停止测试执行。
	failFast = flag.Bool("test.failfast", false, "do not start new tests after the first test failure")

	// 创建配置文件等的目录。从
	// /“go test”运行时，二进制文件始终在包的源目录中运行；
	// 此标志允许“go test”告诉二进制文件在运行“go test”命令的目录中写入文件。
	outputDir = flag.String("test.outputdir", "", "write profiles to `dir`")
	// 运行测试时报告；违约对成功是沉默的。
	chatty = flag.Bool("test.v", false, "verbose: print additional output")
	count = flag.Uint("test.count", 1, "run tests and benchmarks `n` times")
	coverProfile = flag.String("test.coverprofile", "", "write a coverage profile to `file`")
	matchList = flag.String("test.list", "", "list tests, examples, and benchmarks matching `regexp` then exit")
	match = flag.String("test.run", "", "run only tests and examples matching `regexp`")
	memProfile = flag.String("test.memprofile", "", "write an allocation profile to `file`")
	memProfileRate = flag.Int("test.memprofilerate", 0, "set memory allocation profiling `rate` (see runtime.MemProfileRate)")
	cpuProfile = flag.String("test.cpuprofile", "", "write a cpu profile to `file`")
	blockProfile = flag.String("test.blockprofile", "", "write a goroutine blocking profile to `file`")
	blockProfileRate = flag.Int("test.blockprofilerate", 1, "set blocking profile `rate` (see runtime.SetBlockProfileRate)")
	mutexProfile = flag.String("test.mutexprofile", "", "write a mutex contention profile to the named file after execution")
	mutexProfileFraction = flag.Int("test.mutexprofilefraction", 1, "if >= 0, calls runtime.SetMutexProfileFraction()")
	panicOnExit0 = flag.Bool("test.paniconexit0", false, "panic on call to os.Exit(0)")
	traceFile = flag.String("test.trace", "", "write an execution trace to `file`")
	timeout = flag.Duration("test.timeout", 0, "panic test binary after duration `d` (default 0, timeout disabled)")
	cpuListStr = flag.String("test.cpu", "", "comma-separated `list` of cpu counts to run each test with")
	parallel = flag.Int("test.parallel", runtime.GOMAXPROCS(0), "run at most `n` tests in parallel")
	testlog = flag.String("test.testlogfile", "", "write test action log to `file` (for use only by cmd/go)")
	shuffle = flag.String("test.shuffle", "off", "randomize the execution order of tests and benchmarks")

	initBenchmarkFlags()
	initFuzzFlags()
}

var (
	// 标志，在初始化期间注册。
	short                *bool
	failFast             *bool
	outputDir            *string
	chatty               *bool
	count                *uint
	coverProfile         *string
	matchList            *string
	match                *string
	memProfile           *string
	memProfileRate       *int
	cpuProfile           *string
	blockProfile         *string
	blockProfileRate     *int
	mutexProfile         *string
	mutexProfileFraction *int
	panicOnExit0         *bool
	traceFile            *string
	timeout              *time.Duration
	cpuListStr           *string
	parallel             *int
	shuffle              *string
	testlog              *string

	haveExamples bool // 有例子吗？

	cpuList     []int
	testlogFile *os.File

	numFailed uint32 // 测试失败次数
)

type chattyPrinter struct {
	w          io.Writer
	lastNameMu sync.Mutex // 卫士姓氏
	lastName   string     // 聊天模式下最后打印的测试名称
}

func newChattyPrinter(w io.Writer) *chattyPrinter {
	return &chattyPrinter{w: w}
}

// Updatef将有关指定测试状态的消息打印到w。
// 
// 格式化的消息必须包含测试名称本身。
func (p *chattyPrinter) Updatef(testName, format string, args ...any) {
	p.lastNameMu.Lock()
	defer p.lastNameMu.Unlock()

	// 由于该消息已经暗示与特定的新测试相关，
	// 我们不需要检查旧测试名称是什么，也不需要为其记录额外的控制行
	// 。（不管怎样，我们正在更新它，当前消息已经包含了
	// 测试名称。）
	p.lastName = testName
	fmt.Fprintf(p.w, format, args...)
}

// Printf打印一条由指定测试生成的消息，该消息不一定提及该测试的名称本身。
func (p *chattyPrinter) Printf(testName, format string, args ...any) {
	p.lastNameMu.Lock()
	defer p.lastNameMu.Unlock()

	if p.lastName == "" {
		p.lastName = testName
	} else if p.lastName != testName {
		fmt.Fprintf(p.w, "=== CONT  %s\n", testName)
		p.lastName = testName
	}

	fmt.Fprintf(p.w, format, args...)
}

// 跳过
const maxStackLen = 50

// common保存T和B之间的公共元素，
// 捕获常见方法，如Errorf。
type common struct {
	mu          sync.RWMutex         // 保护这组字段
	output      []byte               // 由测试或基准生成的输出。
	w           io.Writer            // 用于flushToParent。
	ran         bool                 // 已执行测试或基准测试（或其子测试之一）。
	failed      bool                 // 测试或基准测试失败。
	skipped     bool                 // 已跳过测试或基准测试。
	done        bool                 // 测试已完成，所有子测试均已完成。
	helperPCs   map[uintptr]struct{} // 写入文件/行信息时要跳过的函数
	helperNames map[string]struct{}  // 转换为函数名的HelperPC 
	cleanups    []func()             // 测试结束时要调用的可选函数
	cleanupName string               // 清除函数的名称。
	cleanupPc   []uintptr            // 调用Cleanup时的堆栈跟踪。
	finished    bool                 // 测试功能已完成。
	inFuzzFn    bool                 // 如果这是一个模糊目标，那么它是否正在运行。

	chatty     *chattyPrinter // 如果设置了chatty标志，则为chattyPrinter的副本。
	bench      bool           // 当前测试是否为基准测试。
	hasSub     int32          // 以原子方式编写。
	raceErrors int            // 测试期间检测到的种族数。
	runner     string         // 运行测试的tRunner的函数名。

	parent   *common
	level    int       // 测试或基准的嵌套深度。
	creator  []uintptr // 如果级别>0，则在父级调用t.Run的点上的堆栈跟踪。
	name     string    // 测试或基准的名称。
	start    time.Time // 时间测试或基准测试已启动
	duration time.Duration
	barrier  chan bool // 向可能启动的并行子测试发出信号。当T.Parallel不存在（B）或不可用（模糊时）时为零。
	signal   chan bool // 发出测试完成的信号。
	sub      []*T      // 要并行运行的子测试队列。

	tempDirMu  sync.Mutex
	tempDir    string
	tempDirErr error
	tempDirSeq int32
}

// 简短报告是否测试。设置短标志。
func Short() bool {
	if short == nil {
		panic("testing: Short called before Init")
	}
	// 捕获从TestMain调用此函数而不首先调用标志的代码。作语法分析
	if !flag.Parsed() {
		panic("testing: Short called before Parse")
	}

	return *short
}

// CoverMode报告测试覆盖模式的设置。
// 值是“set”、“count”或“atomic”。如果未启用测试覆盖率，返回值将为
// 空。
func CoverMode() string {
	return cover.Mode
}

// 详细报告-测试是否正确。设置了v标志。
func Verbose() bool {
	// 简言之相同。
	if chatty == nil {
		panic("testing: Verbose called before Init")
	}
	if !flag.Parsed() {
		panic("testing: Verbose called before Parse")
	}
	return *chatty
}

func (c *common) checkFuzzFn(name string) {
	if c.inFuzzFn {
		panic(fmt.Sprintf("testing: f.%s was called inside the fuzz target, use t.%s instead", name, name))
	}
}

// frameSkip在未标记为帮助程序的函数中，从跳过帧后开始搜索第一个调用方帧
// 并返回该帧。
// 如果搜索到一个tRunner函数，该函数是测试的入口点，而该测试不是子测试，则搜索将停止。
// 必须在保持c.mu的情况下调用此函数。
func (c *common) frameSkip(skip int) runtime.Frame {
	// 如果搜索继续到父测试，我们将不得不暂时保留其mu。如果我们返回，我们需要解锁它。
	shouldUnlock := false
	defer func() {
		if shouldUnlock {
			c.mu.Unlock()
		}
	}()
	var pc [maxStackLen]uintptr
	// 跳过两个额外的帧来说明此函数
	// 和运行时。来电者本身。
	n := runtime.Callers(skip+2, pc[:])
	if n == 0 {
		panic("testing: zero callers found")
	}
	frames := runtime.CallersFrames(pc[:n])
	var firstFrame, prevFrame, frame runtime.Frame
	for more := true; more; prevFrame = frame {
		frame, more = frames.Next()
		if frame.Function == "runtime.gopanic" {
			continue
		}
		if frame.Function == c.cleanupName {
			frames = runtime.CallersFrames(c.cleanupPc)
			continue
		}
		if firstFrame.PC == 0 {
			firstFrame = frame
		}
		if frame.Function == c.runner {
			// 我们一直到tRunner调用
			// 测试函数（因此用户必须有
			// 从测试函数内部调用tb.Helper）。
			// 如果这是顶级测试，只需跳到测试函数本身即可。
			// 如果我们在子测试中，请继续在父测试中搜索，
			// 从创建此子测试的调用Run开始。
			if c.level > 1 {
				frames = runtime.CallersFrames(c.creator)
				parent := c.parent
				// 在这一点之后，我们不再看当前的c，
				// 所以我们应该解锁它的mu，除非它是原始接收器，
				// 在这种情况下，我们的调用者不希望我们这样做。
				if shouldUnlock {
					c.mu.Unlock()
				}
				c = parent
				// 当我们不再需要c.mu时，记得解锁它，要么因为我们提升了另一个嵌套级别，要么因为我们返回了。
				shouldUnlock = true
				c.mu.Lock()
				continue
			}
			return prevFrame
		}
		// 如果我们上次进行转换后添加了更多的助手电脑
		if c.helperNames == nil {
			c.helperNames = make(map[string]struct{})
			for pc := range c.helperPCs {
				c.helperNames[pcToName(pc)] = struct{}{}
			}
		}
		if _, ok := c.helperNames[frame.Function]; !ok {
			// 找到了一个不在helper函数中的框架。
			return frame
		}
	}
	return firstFrame
}

// 装饰在字符串前面加上调用站点的文件和行
// 并在需要时插入最后的换行符和缩进空格进行格式化。
// 必须在保持c.mu的情况下调用此函数。
func (c *common) decorate(s string, skip int) string {
	frame := c.frameSkip(skip)
	file := frame.File
	line := frame.Line
	if file != "" {
		// 在最后一个文件名分隔符处截断文件名。
		if index := strings.LastIndex(file, "/"); index >= 0 {
			file = file[index+1:]
		} else if index = strings.LastIndex(file, "\\"); index >= 0 {
			file = file[index+1:]
		}
	} else {
		file = "???"
	}
	if line == 0 {
		line = 1
	}
	buf := new(strings.Builder)
	// 每行缩进至少4个空格。
	buf.WriteString("    ")
	fmt.Fprintf(buf, "%s:%d: ", file, line)
	lines := strings.Split(s, "\n")
	if l := len(lines); l > 1 && lines[l-1] == "" {
		lines = lines[:l-1]
	}
	for i, line := range lines {
		if i > 0 {
			// 第二行和后续行缩进了额外的4个空格。
			buf.WriteString("\n        ")
		}
		buf.WriteString(line)
	}
	buf.WriteByte('\n')
	return buf.String()
}

// flushToParent在使用给定格式和参数首次写入头
// 后，将c.output写入父级。
func (c *common) flushToParent(testName, format string, args ...any) {
	p := c.parent
	p.mu.Lock()
	defer p.mu.Unlock()

	c.mu.Lock()
	defer c.mu.Unlock()

	if len(c.output) > 0 {
		format += "%s"
		args = append(args[:len(args):len(args)], c.output)
		c.output = c.output[:0] // 但为什么？
	}

	if c.chatty != nil && p.w == c.chatty.w {
		// 我们正在刷新到实际输出，因此请跟踪该输出是否与特定测试关联（具体来说，下一个输出
		// 与该测试*不关联）。ABCFDG 
		// 无论是人类还是cmd/test2json都无法轻松解析这些内容。
		// （请参阅https:
		c.chatty.Updatef(testName, format, args...)
	} else {
		// 我们正在刷新父测试的输出缓冲区，当它最终刷新到stdout时，它将跟随一个测试名称头。
		fmt.Fprintf(p.w, format, args...)
	}
}

type indenter struct {
	c *common
}

func (w indenter) Write(b []byte) (n int, err error) {
	n = len(b)
	for len(b) > 0 {
		end := bytes.IndexByte(b, '\n')
		if end == -1 {
			end = len(b)
		} else {
			end++
		}
		// 四个空格的缩进将把破折号与父测试的状态
		// 指示符整齐地对齐。
		const indent = "    "
		w.c.output = append(w.c.output, indent...)
		w.c.output = append(w.c.output, b[:end]...)
		b = b[end:]
	}
	return
}

// fmtDuration返回一个表示d的字符串，在e表格“87.00s”。
func fmtDuration(d time.Duration) string {
	return fmt.Sprintf("%.2fs", d.Seconds())
}

// TB是T、B和F的通用接口。
type TB interface {
	Cleanup(func())
	Error(args ...any)
	Errorf(format string, args ...any)
	Fail()
	FailNow()
	Failed() bool
	Fatal(args ...any)
	Fatalf(format string, args ...any)
	Helper()
	Log(args ...any)
	Logf(format string, args ...any)
	Name() string
	Setenv(key, value string)
	Skip(args ...any)
	SkipNow()
	Skipf(format string, args ...any)
	Skipped() bool
	TempDir() string

	// 是一种私有方法，用于防止用户实现
	// 接口，因此将来添加到该接口上不会违反Go 1兼容性。
	private()
}

var _ TB = (*T)(nil)
var _ TB = (*B)(nil)

// T是传递给测试函数的类型，用于管理测试状态并支持格式化的测试日志。
// 
// 当测试函数返回或调用任何方法
// FailNow、Fatal、Fatalf、SkipNow、Skip或Skipf时，测试结束。这些方法以及并行方法只能从运行
// 测试函数的goroutine调用。
// 
// 其他报告方法，如日志和错误的变化，
// 可以从多个goroutine同时调用。
type T struct {
	common
	isParallel bool
	isEnvSet   bool
	context    *testContext // 用于运行测试和子测试。
}

func (c *common) private() {}

// Name返回正在运行的（子）测试或基准的名称。
// 
// 名称将包括测试名称以及任何嵌套子测试的名称。如果两个同级子测试具有相同的名称，
// name将附加一个后缀，以保证返回的名称是唯一的。
func (c *common) Name() string {
	return c.name
}

func (c *common) setRan() {
	if c.parent != nil {
		c.parent.setRan()
	}
	c.mu.Lock()
	defer c.mu.Unlock()
	c.ran = true
}

// Fail将函数标记为已失败，但仍继续执行。
func (c *common) Fail() {
	if c.parent != nil {
		c.parent.Fail()
	}
	c.mu.Lock()
	defer c.mu.Unlock()
	// c.done需要被锁定，以将检查同步到父测试中的c.done。
	if c.done {
		panic("Fail in goroutine after " + c.name + " has completed")
	}
	c.failed = true
}

// 失败报告函数是否失败。
func (c *common) Failed() bool {
	c.mu.RLock()
	failed := c.failed
	c.mu.RUnlock()
	return failed || c.raceErrors+race.Errors() > 0
}

// FailNow通过调用runtime将函数标记为已失败并停止其执行
// 。Goexit（然后运行
// 当前goroutine中的所有延迟调用）。
// 执行将在下一个测试或基准测试中继续。
// 必须从运行
// 测试或基准函数的goroutine调用FailNow，而不是从测试期间创建的其他goroutine 
// 调用。调用FailNow并不能阻止
// 其他goroutines。
func (c *common) FailNow() {
	c.checkFuzzFn("FailNow")
	c.Fail()

	// 正在调用运行时。Goexit将退出goroutine，它将运行此goroutine中的延迟函数，它将最终运行tRunner中的延迟行，它将向测试循环发送信号，表明此测试已完成。
	// 
	// 此代码的早期版本为：
	// 
	// c.duration=。。。
	// c.signal<-c.self 
	// runtime。Goexit（）
	// 
	// 这个以前的版本复制了代码（不管怎样，这些行都是在
	// tRunner中），但更糟糕的是，goroutine在运行时会撕裂
	// 。Goexit不保证在测试退出前完成
	// 。如果一个测试推迟了一个重要的清理
	// 函数（比如删除临时文件），那么不能保证
	// 它会在测试失败时运行。因为我们现在在
	// 一个栈顶延迟函数期间发送c.signal，所以我们知道发送
	// 只有在任何其他堆叠延迟完成后才会发生。
	c.mu.Lock()
	c.finished = true
	c.mu.Unlock()
	runtime.Goexit()
}

// 日志生成输出。它总是在相同的堆栈深度。
func (c *common) log(s string) {
	c.logDepth(s, 3) // logDepth+log+公共函数
}

// logDepth以任意堆栈深度生成输出。
func (c *common) logDepth(s string, depth int) {
	c.mu.Lock()
	defer c.mu.Unlock()
	if c.done {
		// 此测试已完成。尝试将此消息
		// 记录到我们的家长那里。如果我们没有父母，惊慌失措。
		for parent := c.parent; parent != nil; parent = parent.parent {
			parent.mu.Lock()
			defer parent.mu.Unlock()
			if !parent.done {
				parent.output = append(parent.output, parent.decorate(s, depth+1)...)
				return
			}
		}
		panic("Log in goroutine after " + c.name + " has completed: " + s)
	} else {
		if c.chatty != nil {
			if c.bench {
				// 基准不打印===CONT，所以我们应该跳过测试
				// 打印机，直接打印到标准输出。
				fmt.Print(c.decorate(s, depth+1))
			} else {
				c.chatty.Printf(c.name, "%s", c.decorate(s, depth+1))
			}

			return
		}
		c.output = append(c.output, c.decorate(s, depth+1)...)
	}
}

// 日志使用默认格式设置其参数的格式，类似于Println，
// 并将文本记录在错误日志中。对于测试，仅当
// 测试失败或-test时，才会打印文本。设置了v标志。对于基准测试，文本总是
// 打印出来，以避免性能取决于-test的值。v旗。
func (c *common) Log(args ...any) {
	c.checkFuzzFn("Log")
	c.log(fmt.Sprintln(args...))
}

// Logf根据与Printf类似的格式对其参数进行格式化，并且
// 将文本记录在错误日志中。如果未提供，则添加最后一个换行符。对于
// 测试，仅当测试失败或-测试失败时，才会打印文本。v标志为
// 设置。对于基准测试，总是打印文本以避免性能
// 取决于-test的值。v旗。
func (c *common) Logf(format string, args ...any) {
	c.checkFuzzFn("Logf")
	c.log(fmt.Sprintf(format, args...))
}

// 错误相当于日志后跟失败。
func (c *common) Error(args ...any) {
	c.checkFuzzFn("Error")
	c.log(fmt.Sprintln(args...))
	c.Fail()
}

// Errorf相当于Logf，后跟Fail。
func (c *common) Errorf(format string, args ...any) {
	c.checkFuzzFn("Errorf")
	c.log(fmt.Sprintf(format, args...))
	c.Fail()
}

// 致命等同于日志后跟FailNow。
func (c *common) Fatal(args ...any) {
	c.checkFuzzFn("Fatal")
	c.log(fmt.Sprintln(args...))
	c.FailNow()
}

// Fatalf相当于Logf后跟FailNow。
func (c *common) Fatalf(format string, args ...any) {
	c.checkFuzzFn("Fatalf")
	c.log(fmt.Sprintf(format, args...))
	c.FailNow()
}

// Skip相当于Log后跟SkipNow。
func (c *common) Skip(args ...any) {
	c.checkFuzzFn("Skip")
	c.log(fmt.Sprintln(args...))
	c.SkipNow()
}

// Skipf等同于Logf，后跟SkipNow。
func (c *common) Skipf(format string, args ...any) {
	c.checkFuzzFn("Skipf")
	c.log(fmt.Sprintf(format, args...))
	c.SkipNow()
}

// SkipNow通过调用runtime将测试标记为已跳过，并停止其执行。戈希特。
// 如果一个测试失败（请参阅Error，Errorf，Fail），然后被跳过，
// 它仍然被认为失败。
// 执行将在下一个测试或基准测试中继续。另见下文。必须从运行测试的goroutine调用SkipNow，而不是从测试期间创建的其他goroutine调用SkipNow。调用SkipNow并不能阻止
// 其他的goroutines。
func (c *common) SkipNow() {
	c.checkFuzzFn("SkipNow")
	c.mu.Lock()
	c.skipped = true
	c.finished = true
	c.mu.Unlock()
	runtime.Goexit()
}

// 跳过报告是否跳过了测试。
func (c *common) Skipped() bool {
	c.mu.RLock()
	defer c.mu.RUnlock()
	return c.skipped
}

// Helper将调用函数标记为测试助手函数。
// 打印文件和行信息时，该功能将被跳过。
// 可以从多个goroutine同时调用Helper。
func (c *common) Helper() {
	c.mu.Lock()
	defer c.mu.Unlock()
	if c.helperPCs == nil {
		c.helperPCs = make(map[uintptr]struct{})
	}
	// 在此处重复callerName中的代码以保存遍历堆栈帧
	var pc [1]uintptr
	n := runtime.Callers(2, pc[:]) // 跳过运行时。调用方+助手
	if n == 0 {
		panic("testing: zero callers found")
	}
	if _, found := c.helperPCs[pc[0]]; !found {
		c.helperPCs[pc[0]] = struct{}{}
		c.helperNames = nil // 下次需要时将重新创建映射
	}
}

// 清除注册一个函数，在测试（或子测试）及其所有
// 子测试完成时调用。清理函数将在最后添加的
// 第一次调用顺序中调用。
func (c *common) Cleanup(f func()) {
	c.checkFuzzFn("Cleanup")
	var pc [maxStackLen]uintptr
	// 跳过两个额外的帧来说明此函数和运行时。来电者本身。
	n := runtime.Callers(2, pc[:])
	cleanupPc := pc[:n]

	fn := func() {
		defer func() {
			c.mu.Lock()
			defer c.mu.Unlock()
			c.cleanupName = ""
			c.cleanupPc = nil
		}()

		name := callerName(0)
		c.mu.Lock()
		c.cleanupName = name
		c.cleanupPc = cleanupPc
		c.mu.Unlock()

		f()
	}

	c.mu.Lock()
	defer c.mu.Unlock()
	c.cleanups = append(c.cleanups, fn)
}

// TempDir返回一个临时目录供测试使用。
// 当测试和
// 其所有子测试完成时，该目录将通过清理自动删除。
// 对t.TempDir的每次后续调用都会返回一个唯一的目录；
// 如果目录创建失败，TempDir通过调用Fatal终止测试。
func (c *common) TempDir() string {
	c.checkFuzzFn("TempDir")
	// 对测试创建的所有临时目录使用单亲目录
	// 每个目录按顺序编号。
	c.tempDirMu.Lock()
	var nonExistent bool
	if c.tempDir == "" { // 通常情况下，js/wasm 
		nonExistent = true
	} else {
		_, err := os.Stat(c.tempDir)
		nonExistent = os.IsNotExist(err)
		if err != nil && !nonExistent {
			c.Fatalf("TempDir: %v", err)
		}
	}

	if nonExistent {
		c.Helper()

		// 将目录名中不寻常的字符（如路径分隔符或
		// 与globs交互的字符）删除到
		// 避免意外操作系统。MkdirTemp行为。
		mapper := func(r rune) rune {
			if r < utf8.RuneSelf {
				const allowed = "!#$%&()+,-.=@^_{}~ "
				if '0' <= r && r <= '9' ||
					'a' <= r && r <= 'z' ||
					'A' <= r && r <= 'Z' {
					return r
				}
				if strings.ContainsRune(allowed, r) {
					return r
				}
			} else if unicode.IsLetter(r) || unicode.IsNumber(r) {
				return r
			}
			return -1
		}
		pattern := strings.Map(mapper, c.Name())
		c.tempDir, c.tempDirErr = os.MkdirTemp("", pattern)
		if c.tempDirErr == nil {
			c.Cleanup(func() {
				if err := removeAll(c.tempDir); err != nil {
					c.Errorf("TempDir RemoveAll cleanup: %v", err)
				}
			})
		}
	}
	c.tempDirMu.Unlock()

	if c.tempDirErr != nil {
		c.Fatalf("TempDir: %v", c.tempDirErr)
	}
	seq := atomic.AddInt32(&c.tempDirSeq, 1)
	dir := fmt.Sprintf("%s%c%03d", c.tempDir, os.PathSeparator, seq)
	if err := os.Mkdir(dir, 0777); err != nil {
		c.Fatalf("TempDir: %v", err)
	}
	return dir
}

// removeAll就像操作系统。移除所有，但重试Windows“访问被拒绝”
// 在任意超时之前出现错误。
// 
// 已知这些错误至少在
// windows-amd64-2012 builder上错误发生(https:
// 失败的情况下，失败的测试可能需要更长的时间才能失败，但一旦测试成功，额外的延迟就会消失。
func removeAll(path string) error {
	const arbitraryTimeout = 2 * time.Second
	var (
		start     time.Time
		nextSleep = 1 * time.Millisecond
	)
	for {
		err := os.RemoveAll(path)
		if !isWindowsAccessDenied(err) {
			return err
		}
		if start.IsZero() {
			start = time.Now()
		} else if d := time.Since(start) + nextSleep; d >= arbitraryTimeout {
			return err
		}
		time.Sleep(nextSleep)
		nextSleep += time.Duration(rand.Int63n(int64(nextSleep)))
	}
}

// Setenv调用操作系统。Setenv（key，value）并使用Cleanup来
// 在测试后将环境变量恢复为其原始值
// 。
// 
// 这不能用于并行测试。
func (c *common) Setenv(key, value string) {
	c.checkFuzzFn("Setenv")
	prevValue, ok := os.LookupEnv(key)

	if err := os.Setenv(key, value); err != nil {
		c.Fatalf("cannot set environment variable: %v", err)
	}

	if ok {
		c.Cleanup(func() {
			os.Setenv(key, prevValue)
		})
	} else {
		c.Cleanup(func() {
			os.Unsetenv(key)
		})
	}
}

// runCleanup是一个参数。
type panicHandling int

const (
	normalPanic panicHandling = iota
	recoverAndReturnPanic
)

// 在测试结束时调用runCleanup。
// 如果catchPanic为true，则将捕捉恐慌，并返回恢复的
// 值（如果有）。
func (c *common) runCleanup(ph panicHandling) (panicVal any) {
	if ph == recoverAndReturnPanic {
		defer func() {
			panicVal = recover()
		}()
	}

	// 确保如果一个清理函数崩溃，
	// 我们仍然运行剩余的清理函数。
	defer func() {
		c.mu.Lock()
		recur := len(c.cleanups) > 0
		c.mu.Unlock()
		if recur {
			c.runCleanup(normalPanic)
		}
	}()

	for {
		var cleanup func()
		c.mu.Lock()
		if len(c.cleanups) > 0 {
			last := len(c.cleanups) - 1
			cleanup = c.cleanups[last]
			c.cleanups = c.cleanups[:last]
		}
		c.mu.Unlock()
		if cleanup == nil {
			return nil
		}
		cleanup()
	}
}

// callerName在跳过帧后为调用者提供函数名（用包路径限定）
// （其中0表示当前函数）。
func callerName(skip int) string {
	var pc [1]uintptr
	n := runtime.Callers(skip+2, pc[:]) // 跳过+运行时。呼叫者+呼叫者姓名
	if n == 0 {
		panic("testing: zero callers found")
	}
	return pcToName(pc[0])
}

func pcToName(pc uintptr) string {
	pcs := []uintptr{pc}
	frames := runtime.CallersFrames(pcs)
	frame, _ := frames.Next()
	return frame.Function
}

// 并行信号表示此测试将与（且仅与）
// 其他并行测试并行运行。由于使用
// /-test而多次运行测试时。计数或测试。cpu，单个测试的多个实例从未在
// 中并行运行。
func (t *T) Parallel() {
	if t.isParallel {
		panic("testing: t.Parallel called multiple times")
	}
	if t.isEnvSet {
		panic("testing: t.Parallel called after t.Setenv; cannot set environment variables in parallel tests")
	}
	t.isParallel = true
	if t.parent.barrier == nil {
		// T.并行在模糊化时没有效果。
		// 多个进程可以并行运行，但每个进程一次只能运行一个输入
		// 因此我们可以将崩溃归因于特定的输入。
		return
	}

	// 我们不想在测试持续时间中包含等待串行测试的时间。记录到目前为止经过的时间，然后重置
	// 计时器。
	t.duration += time.Since(t.start)

	// 添加到家长发布的测试列表中。
	t.parent.sub = append(t.parent.sub, t)
	t.raceErrors += race.Errors()

	if t.chatty != nil {
		// 不幸的是，尽管暂停表示指定的测试*没有
		// 不再*运行，cmd/test2json将其解释为更改活动测试
		// 以进行日志解析。我们可以修复cmd/test2json，但
		// 无法修复现有的第三方工具部署，这些工具已经将
		// 发布到较旧的cmd/test2json版本中，所以现在仅修复cmd/test2json 
		// 是不够的。
		t.chatty.Updatef(t.name, "=== PAUSE %s\n", t.name)
	}

	t.signal <- true   // 释放调用测试。
	<-t.parent.barrier // 等待父测试完成。
	t.context.waitParallel()

	if t.chatty != nil {
		t.chatty.Updatef(t.name, "=== CONT  %s\n", t.name)
	}

	t.start = time.Now()
	t.raceErrors += -race.Errors()
}

// Setenv调用操作系统。Setenv（key，value）并使用Cleanup来
// 在测试后将环境变量恢复为其原始值
// 。
// 
// 这不能用于并行测试。
func (t *T) Setenv(key, value string) {
	if t.isParallel {
		panic("testing: t.Setenv called after t.Parallel; cannot set environment variables in parallel tests")
	}

	t.isEnvSet = true

	t.common.Setenv(key, value)
}

// InternalTest是一个内部类型，但由于它是跨包的，所以被导出；
// 它是“go test”命令实现的一部分。
type InternalTest struct {
	Name string
	F    func(*T)
}

var errNilPanicOrGoexit = errors.New("test executed panic(nil) or runtime.Goexit")

func tRunner(t *T, fn func(t *T)) {
	t.runner = callerName(0)

	// 当此goroutine完成时，可能是因为fn（t）
	// 返回正常，或者是因为测试失败触发了
	// 对运行时的调用。Goexit，记录持续时间并发送
	// 一个信号，表示测试已完成。
	defer func() {
		if t.Failed() {
			atomic.AddUint32(&numFailed, 1)
		}

		if t.raceErrors+race.Errors() > 0 {
			t.Errorf("race detected during execution of test")
		}

		// 检查测试是否恐慌或退出不当。
		// 
		// 如果在正常测试中发生这种情况，请打印输出，但继续恐慌。
		// tRunner在其自己的goroutine中被调用，因此这将终止进程。
		// 
		// 如果在模糊化时发生这种情况，请从恐慌中恢复，并将其视为正常故障。为了找到导致恐慌的短输入，这个过程保持运行是很重要的。
		err := recover()
		signal := true

		t.mu.RLock()
		finished := t.finished
		t.mu.RUnlock()
		if !finished && err == nil {
			err = errNilPanicOrGoexit
			for p := t.parent; p != nil; p = p.parent {
				p.mu.RLock()
				finished = p.finished
				p.mu.RUnlock()
				if finished {
					t.Errorf("%v: subtest may have called FailNow on a parent test", err)
					err = nil
					signal = false
					break
				}
			}
		}

		if err != nil && t.context.isFuzzing {
			prefix := "panic: "
			if err == errNilPanicOrGoexit {
				prefix = ""
			}
			t.Errorf("%s%s\n%s\n", prefix, err, string(debug.Stack()))
			t.mu.Lock()
			t.finished = true
			t.mu.Unlock()
			err = nil
		}

		// 使用延迟调用确保我们报告测试是
		// 完成的，即使清除函数调用t.FailNow。见第41355期。
		didPanic := false
		defer func() {
			if didPanic {
				return
			}
			if err != nil {
				panic(err)
			}
			// 只有在没有死机的情况下才报告测试完成，否则测试二进制文件可以在死机报告给用户之前退出。见第41479期。
			t.signal <- signal
		}()

		doPanic := func(err any) {
			t.Fail()
			if r := t.runCleanup(recoverAndReturnPanic); r != nil {
				t.Logf("cleanup panicked with %v", r)
			}
			// 在死之前将输出日志刷新到根目录。
			for root := &t.common; root.parent != nil; root = root.parent {
				root.mu.Lock()
				root.duration += time.Since(root.start)
				d := root.duration
				root.mu.Unlock()
				root.flushToParent(root.name, "--- FAIL: %s (%s)\n", root.name, fmtDuration(d))
				if r := root.parent.runCleanup(recoverAndReturnPanic); r != nil {
					fmt.Fprintf(root.parent.w, "cleanup panicked with %v", r)
				}
			}
			didPanic = true
			panic(err)
		}
		if err != nil {
			doPanic(err)
		}

		t.duration += time.Since(t.start)

		if len(t.sub) > 0 {
			// 运行并行子测试。
			// 减少此测试的运行计数。
			t.context.release()
			// 释放并行子测试。
			close(t.barrier)
			// 等待子测试完成。
			for _, sub := range t.sub {
				<-sub.signal
			}
			cleanupStart := time.Now()
			err := t.runCleanup(recoverAndReturnPanic)
			t.duration += time.Since(cleanupStart)
			if err != nil {
				doPanic(err)
			}
			if !t.isParallel {
				// 重新获取顺序测试的计数。请参阅Run中的评论。
				t.context.waitParallel()
			}
		} else if t.isParallel {
			// 仅当此测试作为并行
			// 测试运行时，才释放此测试的计数。请参阅Run方法中的注释。
			t.context.release()
		}
		t.report() // 完成所有子测试后报告。

		// 不要锁定t。如果用户没有适当地同步goroutine，则允许race detector检测race。
		t.done = true
		if t.parent != nil && atomic.LoadInt32(&t.hasSub) == 0 {
			t.setRan()
		}
	}()
	defer func() {
		if len(t.sub) == 0 {
			t.runCleanup(normalPanic)
		}
	}()

	t.start = time.Now()
	t.raceErrors = -race.Errors()
	fn(t)

	// 调用FailNow时，将不会执行此处以外的代码
	t.mu.Lock()
	t.finished = true
	t.mu.Unlock()
}

// 运行f作为名为name的t的子测试。它在一个单独的goroutine 
// 中运行f，并阻塞，直到f返回或调用t.Parallel成为并行测试。
// Run报告f是否成功（或者至少在调用t.Parallel之前没有失败）。
// 
// 可以从多个goroutine同时调用Run，但所有此类调用
// 必须在t的外部测试函数返回之前返回。
func (t *T) Run(name string, f func(t *T)) bool {
	atomic.StoreInt32(&t.hasSub, 1)
	testName, ok, _ := t.context.match.fullName(&t.common, name)
	if !ok || shouldFailFast() {
		return true
	}
	// 记录此调用点的堆栈跟踪，这样，如果在单独堆栈中运行的子测试
	// 函数被标记为帮助程序，我们可以
	// 继续将堆栈遍历到父测试中。
	var pc [maxStackLen]uintptr
	n := runtime.Callers(2, pc[:])
	t = &T{
		common: common{
			barrier: make(chan bool),
			signal:  make(chan bool, 1),
			name:    testName,
			parent:  &t.common,
			level:   t.level + 1,
			creator: pc[:n],
			chatty:  t.chatty,
		},
		context: t.context,
	}
	t.w = indenter{&t.common}

	if t.chatty != nil {
		t.chatty.Updatef(t.name, "=== RUN   %s\n", t.name)
	}
	// 在调用
	// tRunner之前，我们没有减少此测试的运行计数，并在之后增加它，而是依靠tRunner保持
	// 计数正确。这确保了一系列连续测试在不被抢占的情况下运行
	// 即使它们的父测试是并行测试。如果*parallel==1，这个
	// 可能会特别减少惊喜。
	go tRunner(t, f)
	if !<-t.signal {
		// 此时，其中一个子测试可能对其中一个
		// 父测试调用了FailNow。继续终止这条链。
		runtime.Goexit()
	}
	return !t.failed
}

// Deadline报告测试二进制文件超过-timeout标志指定的超时的时间。
// 
// 如果-timeout标志指示“无超时”（0），则ok结果为false。
func (t *T) Deadline() (deadline time.Time, ok bool) {
	deadline = t.context.deadline
	return deadline, !deadline.IsZero()
}

// testContext保存所有测试通用的所有字段。这包括
// 最多运行*个并行测试的同步原语。
type testContext struct {
	match    *matcher
	deadline time.Time

	// 在生成模糊目标的随机输入
	// 时使用的上下文中，isFuzzing是真的。当运行普通测试时，isFuzzing为false；当作为单元测试运行fuzz测试时，
	// 为false（不带-fuzz或当-fuzz 
	// 不匹配时）。
	isFuzzing bool

	mu sync.Mutex

	// 用于向准备并行运行的测试发送信号的通道。
	startParallel chan bool

	// running是当前并行运行的测试数。
	// 这不包括等待子测试完成的测试。
	running int

	// numWaiting是等待并行运行的测试数。
	numWaiting int

	// maxParallel是parallel标志的副本。
	maxParallel int
}

func newTestContext(maxParallel int, m *matcher) *testContext {
	return &testContext{
		match:         m,
		startParallel: make(chan bool),
		maxParallel:   maxParallel,
		running:       1, // 将主（顺序）测试的计数设置为1。
	}
}

func (c *testContext) waitParallel() {
	c.mu.Lock()
	if c.running < c.maxParallel {
		c.running++
		c.mu.Unlock()
		return
	}
	c.numWaiting++
	c.mu.Unlock()
	<-c.startParallel
}

func (c *testContext) release() {
	c.mu.Lock()
	if c.numWaiting == 0 {
		c.running--
		c.mu.Unlock()
		return
	}
	c.numWaiting--
	c.mu.Unlock()
	c.startParallel <- true // 选择要运行的等待测试。
}

// 任何人都不应该再使用func Main了。
// 查看func Main上的文档注释，并使用MainStart。
var errMain = errors.New("testing: unexpected use of func Main")

type matchStringOnly func(pat, str string) (bool, error)

func (f matchStringOnly) MatchString(pat, str string) (bool, error)   { return f(pat, str) }
func (f matchStringOnly) StartCPUProfile(w io.Writer) error           { return errMain }
func (f matchStringOnly) StopCPUProfile()                             {}
func (f matchStringOnly) WriteProfileTo(string, io.Writer, int) error { return errMain }
func (f matchStringOnly) ImportPath() string                          { return "" }
func (f matchStringOnly) StartTestLog(io.Writer)                      {}
func (f matchStringOnly) StopTestLog() error                          { return errMain }
func (f matchStringOnly) SetPanicOnExit0(bool)                        {}
func (f matchStringOnly) CoordinateFuzzing(time.Duration, int64, time.Duration, int64, int, []corpusEntry, []reflect.Type, string, string) error {
	return errMain
}
func (f matchStringOnly) RunFuzzWorker(func(corpusEntry) error) error { return errMain }
func (f matchStringOnly) ReadCorpus(string, []reflect.Type) ([]corpusEntry, error) {
	return nil, errMain
}
func (f matchStringOnly) CheckCorpus([]any, []reflect.Type) error { return nil }
func (f matchStringOnly) ResetCoverage()                          {}
func (f matchStringOnly) SnapshotCoverage()                       {}

// Main是一个内部函数，是“go test”命令实现的一部分。
// 它之所以被导出，是因为它是跨包的，并且早于“内部”包。
// 它不再被“go test”使用，而是尽可能多地为其他
// 使用Main模拟“go test”的系统保留，但在测试包中添加新功能时，Main有时无法更新。
// 模拟“go test”的系统应更新为使用Mainstrart。
func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) {
	os.Exit(MainStart(matchStringOnly(matchString), tests, benchmarks, nil, examples).Run())
}

// M是传递给TestMain函数以运行实际测试的类型。
type M struct {
	deps        testDeps
	tests       []InternalTest
	benchmarks  []InternalBenchmark
	fuzzTargets []InternalFuzzTarget
	examples    []InternalExample

	timer     *time.Timer
	afterOnce sync.Once

	numRun int

	// 要传递给操作系统的值。退出，外部测试功能主
	// 线束调用操作系统。使用此代码退出。见#34129。
	exitCode int
}

// testDeps是一个内部接口，其功能由测试生成的主包传递到这个包中。
// 此接口的规范实现是
// testing/internal/testdeps的testdeps。
type testDeps interface {
	ImportPath() string
	MatchString(pat, str string) (bool, error)
	SetPanicOnExit0(bool)
	StartCPUProfile(io.Writer) error
	StopCPUProfile()
	StartTestLog(io.Writer)
	StopTestLog() error
	WriteProfileTo(string, io.Writer, int) error
	CoordinateFuzzing(time.Duration, int64, time.Duration, int64, int, []corpusEntry, []reflect.Type, string, string) error
	RunFuzzWorker(func(corpusEntry) error) error
	ReadCorpus(string, []reflect.Type) ([]corpusEntry, error)
	CheckCorpus([]any, []reflect.Type) error
	ResetCoverage()
	SnapshotCoverage()
}

// MainStart用于“go test”生成的测试。
// 它不打算直接调用，也不受Go 1兼容性文档的约束。
// 它可能会在不同版本之间更改签名。
func MainStart(deps testDeps, tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) *M {
	Init()
	return &M{
		deps:        deps,
		tests:       tests,
		benchmarks:  benchmarks,
		fuzzTargets: fuzzTargets,
		examples:    examples,
	}
}

// 运行测试。它返回一个要传递给操作系统的退出代码。出口
func (m *M) Run() (code int) {
	defer func() {
		code = m.exitCode
	}()

	// 计算m.Run的调用数。
	// 我们只期望1，但我们没有强制执行，
	// 现在在野外有调用m的测试。运行多次。
	// 叹气。戈朗。org/issue/23129。
	m.numRun++

	// TestMain可能已经调用了flag。作语法分析
	if !flag.Parsed() {
		flag.Parse()
	}

	if *parallel < 1 {
		fmt.Fprintln(os.Stderr, "testing: -parallel can only be given a positive integer")
		flag.Usage()
		m.exitCode = 2
		return
	}
	if *matchFuzz != "" && *fuzzCacheDir == "" {
		fmt.Fprintln(os.Stderr, "testing: -test.fuzzcachedir must be set if -test.fuzz is set")
		flag.Usage()
		m.exitCode = 2
		return
	}

	if len(*matchList) != 0 {
		listTests(m.deps.MatchString, m.tests, m.benchmarks, m.fuzzTargets, m.examples)
		m.exitCode = 0
		return
	}

	if *shuffle != "off" {
		var n int64
		var err error
		if *shuffle == "on" {
			n = time.Now().UnixNano()
		} else {
			n, err = strconv.ParseInt(*shuffle, 10, 64)
			if err != nil {
				fmt.Fprintln(os.Stderr, `testing: -shuffle should be "off", "on", or a valid integer:`, err)
				m.exitCode = 2
				return
			}
		}
		fmt.Println("-test.shuffle", n)
		rng := rand.New(rand.NewSource(n))
		rng.Shuffle(len(m.tests), func(i, j int) { m.tests[i], m.tests[j] = m.tests[j], m.tests[i] })
		rng.Shuffle(len(m.benchmarks), func(i, j int) { m.benchmarks[i], m.benchmarks[j] = m.benchmarks[j], m.benchmarks[i] })
	}

	parseCpuList()

	m.before()
	defer m.after()

	// 运行测试、示例和基准测试，除非这是一个模糊工作进程。
	// 工作人员在其父进程完成后开始工作，他们应该
	// 不要重复此工作。
	if !*isFuzzWorker {
		deadline := m.startAlarm()
		haveExamples = len(m.examples) > 0
		testRan, testOk := runTests(m.deps.MatchString, m.tests, deadline)
		fuzzTargetsRan, fuzzTargetsOk := runFuzzTests(m.deps, m.fuzzTargets, deadline)
		exampleRan, exampleOk := runExamples(m.deps.MatchString, m.examples)
		m.stopAlarm()
		if !testRan && !exampleRan && !fuzzTargetsRan && *matchBenchmarks == "" && *matchFuzz == "" {
			fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
		}
		if !testOk || !exampleOk || !fuzzTargetsOk || !runBenchmarks(m.deps.ImportPath(), m.deps.MatchString, m.benchmarks) || race.Errors() > 0 {
			fmt.Println("FAIL")
			m.exitCode = 1
			return
		}
	}

	fuzzingOk := runFuzzing(m.deps, m.fuzzTargets)
	if !fuzzingOk {
		fmt.Println("FAIL")
		if *isFuzzWorker {
			m.exitCode = fuzzWorkerExitCode
		} else {
			m.exitCode = 1
		}
		return
	}

	m.exitCode = 0
	if !*isFuzzWorker {
		fmt.Println("PASS")
	}
	return
}

func (t *T) report() {
	if t.parent == nil {
		return
	}
	dstr := fmtDuration(t.duration)
	format := "--- %s: %s (%s)\n"
	if t.Failed() {
		t.flushToParent(t.name, format, "FAIL", t.name, dstr)
	} else if t.chatty != nil {
		if t.Skipped() {
			t.flushToParent(t.name, format, "SKIP", t.name, dstr)
		} else {
			t.flushToParent(t.name, format, "PASS", t.name, dstr)
		}
	}
}

func listTests(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) {
	if _, err := matchString(*matchList, "non-empty"); err != nil {
		fmt.Fprintf(os.Stderr, "testing: invalid regexp in -test.list (%q): %s\n", *matchList, err)
		os.Exit(1)
	}

	for _, test := range tests {
		if ok, _ := matchString(*matchList, test.Name); ok {
			fmt.Println(test.Name)
		}
	}
	for _, bench := range benchmarks {
		if ok, _ := matchString(*matchList, bench.Name); ok {
			fmt.Println(bench.Name)
		}
	}
	for _, fuzzTarget := range fuzzTargets {
		if ok, _ := matchString(*matchList, fuzzTarget.Name); ok {
			fmt.Println(fuzzTarget.Name)
		}
	}
	for _, example := range examples {
		if ok, _ := matchString(*matchList, example.Name); ok {
			fmt.Println(example.Name)
		}
	}
}

// RunTests是一个内部函数，但由于它是跨包的，所以被导出；
// 它是“go test”命令实现的一部分。
func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool) {
	var deadline time.Time
	if *timeout > 0 {
		deadline = time.Now().Add(*timeout)
	}
	ran, ok := runTests(matchString, tests, deadline)
	if !ran && !haveExamples {
		fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
	}
	return ok
}

func runTests(matchString func(pat, str string) (bool, error), tests []InternalTest, deadline time.Time) (ran, ok bool) {
	ok = true
	for _, procs := range cpuList {
		runtime.GOMAXPROCS(procs)
		for i := uint(0); i < *count; i++ {
			if shouldFailFast() {
				break
			}
			if i > 0 && !ran {
				// 在第一次
				// 迭代中没有要运行的测试。这不会改变，所以没有理由继续尝试。
				break
			}
			ctx := newTestContext(*parallel, newMatcher(matchString, *match, "-test.run"))
			ctx.deadline = deadline
			t := &T{
				common: common{
					signal:  make(chan bool, 1),
					barrier: make(chan bool),
					w:       os.Stdout,
				},
				context: ctx,
			}
			if Verbose() {
				t.chatty = newChattyPrinter(t.w)
			}
			tRunner(t, func(t *T) {
				for _, test := range tests {
					t.Run(test.Name, test.F)
				}
			})
			select {
			case <-t.signal:
			default:
				panic("internal error: tRunner exited without sending on t.signal")
			}
			ok = ok && !t.Failed()
			ran = ran || t.ran
		}
	}
	return ran, ok
}

// 在所有测试之前运行。
func (m *M) before() {
	if *memProfileRate > 0 {
		runtime.MemProfileRate = *memProfileRate
	}
	if *cpuProfile != "" {
		f, err := os.Create(toOutputDir(*cpuProfile))
		if err != nil {
			fmt.Fprintf(os.Stderr, "testing: %s\n", err)
			return
		}
		if err := m.deps.StartCPUProfile(f); err != nil {
			fmt.Fprintf(os.Stderr, "testing: can't start cpu profile: %s\n", err)
			f.Close()
			return
		}
		// 可以保存f，这样之后可以调用f.Close；不值得这么努力。
	}
	if *traceFile != "" {
		f, err := os.Create(toOutputDir(*traceFile))
		if err != nil {
			fmt.Fprintf(os.Stderr, "testing: %s\n", err)
			return
		}
		if err := trace.Start(f); err != nil {
			fmt.Fprintf(os.Stderr, "testing: can't start tracing: %s\n", err)
			f.Close()
			return
		}
		// 可以保存f，这样之后就可以调用f.Close；不值得这么努力。
	}
	if *blockProfile != "" && *blockProfileRate >= 0 {
		runtime.SetBlockProfileRate(*blockProfileRate)
	}
	if *mutexProfile != "" && *mutexProfileFraction >= 0 {
		runtime.SetMutexProfileFraction(*mutexProfileFraction)
	}
	if *coverProfile != "" && cover.Mode == "" {
		fmt.Fprintf(os.Stderr, "testing: cannot use -test.coverprofile because test binary was not built with coverage enabled\n")
		os.Exit(2)
	}
	if *testlog != "" {
		// 注意：不使用toOutputDir。
		// 此文件供cmd/go使用，而非用户。
		var f *os.File
		var err error
		if m.numRun == 1 {
			f, err = os.Create(*testlog)
		} else {
			f, err = os.OpenFile(*testlog, os.O_WRONLY, 0)
			if err == nil {
				f.Seek(0, io.SeekEnd)
			}
		}
		if err != nil {
			fmt.Fprintf(os.Stderr, "testing: %s\n", err)
			os.Exit(2)
		}
		m.deps.StartTestLog(f)
		testlogFile = f
	}
	if *panicOnExit0 {
		m.deps.SetPanicOnExit0(true)
	}
}

// 在所有测试后运行。
func (m *M) after() {
	m.afterOnce.Do(func() {
		m.writeProfiles()
	})

	// 每次运行后恢复PanicOnExit0，因为我们在
	// 每次运行前将其设置为true。否则，如果多次调用m.Run，则表示
	// os的行为。第二次运行后将不会恢复出口（0）。
	if *panicOnExit0 {
		m.deps.SetPanicOnExit0(false)
	}
}

func (m *M) writeProfiles() {
	if *testlog != "" {
		if err := m.deps.StopTestLog(); err != nil {
			fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *testlog, err)
			os.Exit(2)
		}
		if err := testlogFile.Close(); err != nil {
			fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *testlog, err)
			os.Exit(2)
		}
	}
	if *cpuProfile != "" {
		m.deps.StopCPUProfile() // 将配置文件刷新到磁盘
	}
	if *traceFile != "" {
		trace.Stop() // 将跟踪刷新到磁盘
	}
	if *memProfile != "" {
		f, err := os.Create(toOutputDir(*memProfile))
		if err != nil {
			fmt.Fprintf(os.Stderr, "testing: %s\n", err)
			os.Exit(2)
		}
		runtime.GC() // 实现所有统计
		if err = m.deps.WriteProfileTo("allocs", f, 0); err != nil {
			fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *memProfile, err)
			os.Exit(2)
		}
		f.Close()
	}
	if *blockProfile != "" && *blockProfileRate >= 0 {
		f, err := os.Create(toOutputDir(*blockProfile))
		if err != nil {
			fmt.Fprintf(os.Stderr, "testing: %s\n", err)
			os.Exit(2)
		}
		if err = m.deps.WriteProfileTo("block", f, 0); err != nil {
			fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *blockProfile, err)
			os.Exit(2)
		}
		f.Close()
	}
	if *mutexProfile != "" && *mutexProfileFraction >= 0 {
		f, err := os.Create(toOutputDir(*mutexProfile))
		if err != nil {
			fmt.Fprintf(os.Stderr, "testing: %s\n", err)
			os.Exit(2)
		}
		if err = m.deps.WriteProfileTo("mutex", f, 0); err != nil {
			fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *mutexProfile, err)
			os.Exit(2)
		}
		f.Close()
	}
	if cover.Mode != "" {
		coverReport()
	}
}

// toOutputDir返回重新定位到outputDir的文件名（如果需要）。
// 简单的实现可以避免拉入路径/文件路径。
func toOutputDir(path string) string {
	if *outputDir == "" || path == "" {
		return path
	}
	// 在Windows上，这很笨拙，但我们几乎总是可以通过查找驱动器号和冒号来纠正
	// 错误。
	// 绝对路径总是有一个驱动器号（忽略UNC）。
	// 问题：如果path==“C:A”和outputdir==“C:\Go”，则不清楚
	// 该怎么做，但即使这样，path/filepath也没有帮助。
	// 待办事项：值得做得更好吗？可能不会，因为我们这里只有
	// 在go测试的管理之下。
	if runtime.GOOS == "windows" && len(path) >= 2 {
		letter, colon := path[0], path[1]
		if ('a' <= letter && letter <= 'z' || 'A' <= letter && letter <= 'Z') && colon == ':' {
			// 如果路径以驱动器号开头，我们无论如何都要使用它。
			return path
		}
	}
	if os.IsPathSeparator(path[0]) {
		return path
	}
	return fmt.Sprintf("%s%c%s", *outputDir, os.PathSeparator, path)
}

// StartArm会根据请求启动警报。
func (m *M) startAlarm() time.Time {
	if *timeout <= 0 {
		return time.Time{}
	}

	deadline := time.Now().Add(*timeout)
	m.timer = time.AfterFunc(*timeout, func() {
		m.after()
		debug.SetTraceback("all")
		panic(fmt.Sprintf("test timed out after %v", *timeout))
	})
	return deadline
}

// 停止报警关闭报警。
func (m *M) stopAlarm() {
	if *timeout > 0 {
		m.timer.Stop()
	}
}

func parseCpuList() {
	for _, val := range strings.Split(*cpuListStr, ",") {
		val = strings.TrimSpace(val)
		if val == "" {
			continue
		}
		cpu, err := strconv.Atoi(val)
		if err != nil || cpu <= 0 {
			fmt.Fprintf(os.Stderr, "testing: invalid value %q for -test.cpu\n", val)
			os.Exit(1)
		}
		cpuList = append(cpuList, cpu)
	}
	if cpuList == nil {
		cpuList = append(cpuList, runtime.GOMAXPROCS(-1))
	}
}

func shouldFailFast() bool {
	return *failFast && atomic.LoadUint32(&numFailed) > 0
}
